#include "arbol_b_mas.h"

ArbolBMas::ArbolBMas(std::string nombre, unsigned int tam_bloque):ArbolB(nombre,tam_bloque){
	_nodo_actual_ = _NODO_RAIZ_;
	_clave_actual_ = NULL;
}
	
ArbolBMas::~ArbolBMas(){
	if (_clave_actual_ != NULL)
		delete (_clave_actual_);
}

void ArbolBMas::manejar_underflow( Nodo * nodo, Nodo * hijo, bool hijo_derecho ){
	if(hijo->get_nivel() == 0){
		if( !redistribuir_hoja( nodo, hijo, hijo_derecho ) ){
			Debug::get_instance()->mostrar_mensaje("<ARBOL> Se produjo underflow en un nodo del arbol " + this->get_nombre() + ". Se concatenan nodos." );	
			concatenar_hoja(nodo, hijo, hijo_derecho);
		}
		else
			Debug::get_instance()->mostrar_mensaje("<ARBOL> Se produjo underflow en un nodo del arbol " + this->get_nombre() + ". Se pudo redistribuir." );	
	}else{
		if( !redistribuir( nodo, hijo, hijo_derecho ) ){
			Debug::get_instance()->mostrar_mensaje("<ARBOL> Se produjo underflow en un nodo del arbol " + this->get_nombre() + ". Se concatenan nodos." );	
			concatenar(nodo, hijo, hijo_derecho);
		}
		else
			Debug::get_instance()->mostrar_mensaje("<ARBOL> Se produjo underflow en un nodo del arbol " + this->get_nombre() + ". Se pudo redistribuir." );	
	}
}

void ArbolBMas::actualizar_clave(Nodo* padre,TipoDato* claveVieja,TipoDato* claveNueva){
	
	Debug::get_instance()->mostrar_mensaje("<ARBOL> Se actualiza un separador del arbol " + this->get_nombre() + "." );	
	TipoInt  * dato = new TipoInt(0); //Creo un int con un valor cualquiera
	//sabemos que existe la clave a actualizar
	//Me guardo las refs
	unsigned short int ref_d = padre->get_ref_der();
	unsigned short int ref_i = padre->get_ref_izq();
	//quito la claveVIeja dentro del nodo padre
	padre->quitar_elemento(claveVieja);
	//ingreso en el nodo la clave nueva, con el int creado
	padre->ingresar_elemento(claveNueva,dato);
	padre->set_ref_der(ref_d);
	padre->set_ref_izq(ref_i);
	Buffer::get_instance()->guardar_bloque(*this, padre->get_bloque());
	delete dato;
}
				
bool ArbolBMas::equilibrar_hojas(Nodo * hijo, Nodo * vecino ){
	TipoDato * clave_del_vecino = hijo->get_clave_base();
	TipoInt  * dato_del_vecino  = new TipoInt(0);
	//quito el elemento prestado
	vecino->get_clave(clave_del_vecino);
	vecino->get_dato(dato_del_vecino);
	vecino->quitar_elemento();
	//si me queda en underflow el vecino, lo vuelvo a meter
	if( hay_underflow(vecino) ){
		vecino->ingresar_elemento(clave_del_vecino, dato_del_vecino);
		Buffer::get_instance()->guardar_bloque(*this,vecino->get_bloque());	
		delete clave_del_vecino;
		delete dato_del_vecino;	
		return false;
	}
	else{
		//si no hay underflow, quiere decir que le podia prestar, 
		hijo->ingresar_elemento(clave_del_vecino, dato_del_vecino);
		Buffer::get_instance()->guardar_bloque(*this,vecino->get_bloque());
		Buffer::get_instance()->guardar_bloque(*this,hijo->get_bloque());
	}
	delete clave_del_vecino;
	delete dato_del_vecino;
	
	return true;
}

bool ArbolBMas::redistribuir_hoja( Nodo * nodo, Nodo * hijo, bool hijo_derecho ){
	Nodo * vecino = NULL;
	TipoDato * clave_del_vecino = nodo->get_clave_base();
	TipoInt  * dato_del_vecino  = new TipoInt(0);
	bool presto = false;
	
	//discrimino si era el hijo izquierdo o derecho porque me viene posicionado
	//entonces si primero le pido prestado al hijo izquierdo (por convencion), 
	//tengo que tener en cuenta que si no es derecho debo moverme 1 lugar 
	//para la izquierda para obtener el izquierdo del izquierdo
	if(!hijo_derecho){
		bool tenia_anterior = nodo->anterior();
		if( tenia_anterior ){
			//significa que me pude mover, es decir, no estaba en el borde	
			vecino = new Nodo(Buffer::get_instance()->get_bloque(*this, nodo->get_ref_izq()), clave_del_vecino ,dato_del_vecino);
			//me voy al ultimo elem del vecino, que es el que le puedo pedir prestado,lo dejo posicionado
			vecino->ultimo();
			presto = equilibrar_hojas(hijo, vecino);	
			if (presto)
				cambiar_claves(hijo,nodo);
			else{
				nodo->siguiente();
				delete (vecino->get_bloque());
				delete vecino;
			}
		}
		if( !presto ){
			vecino = new Nodo(Buffer::get_instance()->get_bloque(*this, nodo->get_ref_der()), clave_del_vecino ,dato_del_vecino);
			//me voy al primer elem del vecino, que es el que le puedo pedir prestado,lo dejo posicionado
			vecino->primero();
			presto = equilibrar_hojas(hijo, vecino);
			if (presto)
				cambiar_claves(vecino,nodo);
		}		
	}
	else{
		//si era el hijo derecho, no me tengo que desplazar para el izq
		vecino = new Nodo(Buffer::get_instance()->get_bloque(*this, nodo->get_ref_izq()), clave_del_vecino ,dato_del_vecino);
		//me voy al ultimo elem del vecino, que es el que le puedo pedir prestado,lo dejo posicionado
		vecino->ultimo();
		presto = equilibrar_hojas(hijo, vecino);
		if( !presto ){
			//si no presto, avanzo al proximo
			if( nodo->siguiente() ){
				//si pudo avanzar, leo el proximo vecino
				delete (vecino->get_bloque());
				delete vecino;
				vecino = new Nodo(Buffer::get_instance()->get_bloque(*this, nodo->get_ref_der()), clave_del_vecino ,dato_del_vecino);	
				vecino->primero();
				presto = equilibrar_hojas(hijo, vecino);
				if( !presto )
					nodo->anterior();//devuelvo posicionado donde me llego
				else
					cambiar_claves(vecino,nodo);
			}
		}else
			cambiar_claves(hijo,nodo);
	}
	Buffer::get_instance()->guardar_bloque(*this,hijo->get_bloque());	
	delete clave_del_vecino;
	delete dato_del_vecino;
	delete (vecino->get_bloque());
	delete vecino;
	return presto;		
	
}
 		
void ArbolBMas::cambiar_claves(Nodo * nodo,Nodo * padre){
	//obtengo las respectivas claves de los nodos pasados por param
	//del padre me interesa la clave donde esta posicionado
	//del nodo (hijo) me interesa la primera
	nodo->primero();
	TipoDato* claveNueva = nodo->get_clave_base();
	TipoDato* claveVieja = padre->get_clave_base();
	padre->get_clave(claveVieja);
	nodo->get_clave(claveNueva);
	//actualizo la clave del padre, ya que se modifico la primer posicion del hijo derecho
	actualizar_clave(padre,claveVieja,claveNueva);
	//deleteo las claves que cree
	delete claveVieja;
	delete claveNueva;
} 		


void ArbolBMas::concat_interno(NodoBMas* izq, NodoBMas* der, Nodo* padre){
	TipoDato* clave_hijo = this->base->clonar();
	der->primero();
	der->get_clave(clave_hijo); 
	izq->unir(der);
	//saco del indice la clave del hijo que se perdio al unir los nodos
	padre->quitar_elemento(clave_hijo);
	if (padre->vacio()){
		//si el padre quedo vacio, le ingreso los elems del hijo
		//que contiene lo concatenado.  Ya queda con el nivel corresp
		char* contenido = new char[izq->get_bloque()->get_tope()];
		izq->get_bloque()->leer(contenido, 0, izq->get_bloque()->get_tope());
		padre->get_bloque()->escribir(contenido, 0, izq->get_bloque()->get_tope());
		delete[] (contenido);
		TipoDato* clave_base = padre->get_clave_base();
		TipoDato* dato_base = padre->get_dato_base();
		NodoBMas padre_b_mas (padre->get_bloque(), clave_base, dato_base);
		padre_b_mas.set_sig_nodo(Nodo::BAD_REF);
		delete (clave_base);
		delete (dato_base);
		//vacio el hijo
		izq->vaciar();
		//lo agrego como disponible
		bloques_libres->append( izq->get_bloque()->get_num_bloque() );
	}
	//lo agrego al arch de bbll
	bloques_libres->append( der->get_bloque()->get_num_bloque() );	
	delete clave_hijo;		
}

void ArbolBMas::concatenar_hoja(Nodo * padre, Nodo * hijo, bool hijo_derecho){
	//concateno siempre con el izquierdo salvo que sea el izquierdo del
	//primer nodo
	unsigned short int ref = 0;
	bool concateno_con_izq = true;
	if(!hijo_derecho){
		if( !padre->anterior() ){
			ref = padre->get_ref_der();
			concateno_con_izq = false;
		}else
			//si era derecho o no era el de la punta, tomo el de la izquierda
			ref = padre->get_ref_izq();
	}
	else
		ref = padre->get_ref_izq();
		
	TipoDato * clave_padre = this->base->clonar();
	TipoInt  * dato_padre  = new TipoInt(0);
	//obtengo el hijo con el que concateno
	NodoBMas * hijo_concat = new NodoBMas(Buffer::get_instance()->get_bloque(*this, ref), clave_padre, dato_padre);
	NodoBMas * hijo_b_mas = new NodoBMas(hijo->get_bloque(),clave_padre,dato_padre);
	unsigned short sig_concat = hijo_concat->get_sig_nodo();
	unsigned short sig_hijo_b_mas = hijo_b_mas->get_sig_nodo();
	//uno los nodos
	if (concateno_con_izq){
		concat_interno(hijo_concat,hijo_b_mas,padre);
		hijo_concat->set_sig_nodo(sig_hijo_b_mas);
	}else{
		concat_interno(hijo_b_mas,hijo_concat,padre);
		hijo_b_mas->set_sig_nodo(sig_concat);
	}
	
	//guardo el hijo modificado
	Buffer::get_instance()->guardar_bloque(*this, hijo_concat->get_bloque());
	Buffer::get_instance()->guardar_bloque(*this, hijo_b_mas->get_bloque());	
	//guardo el padre modificado
	Buffer::get_instance()->guardar_bloque(*this, padre->get_bloque());
	delete (hijo_concat->get_bloque());
	delete hijo_concat;
	delete hijo_b_mas;
	delete dato_padre;
	delete clave_padre;
	
}


bool ArbolBMas::manejar_overflow(Nodo * padre, Nodo * Hijo, ElemNodo * elem){
	//Chequeo que sea hoja, de ser asi maneja el underflow diferente,sino como arbol b
	if (Hijo->get_nivel() == 0)
		return manejar_overflow_hoja(padre,Hijo,elem);
	else
		return ArbolB::manejar_overflow(padre,Hijo,elem);
}

bool ArbolBMas::manejar_overflow_hoja(Nodo * padre, Nodo * hijo, ElemNodo * elem){
	
	Debug::get_instance()->mostrar_mensaje("<ARBOL> Se produjo un overflow en una hoja del arbol " + this->get_nombre() + ".");
	//obtengo el bloque nuevo y lo guardo en un nodo B mas, encapsulo ademas el hijo en un nodo b mas
	NodoBMas * nodo_nuevo = new NodoBMas(get_bloque_libre(0), elem->clave, elem->dato);
	NodoBMas * nodo_hijo = new NodoBMas(hijo->get_bloque(),elem->clave, elem->dato);
	//el nodo hijo tiene como siguiente hasta el momento la ref derecha del padre
	//nodo_hijo->set_sig_nodo(padre->get_ref_der());
	
	//divido el nodo hijo en dos, con el dato que desborda.
	//primer mitad en nodo_hijo, segunda mitad en nodo_nuevo, el elem nuevo se inserta donde corresponda
	nodo_hijo->ingresar_con_split(nodo_nuevo, elem->clave, elem->dato);
	
	//me posiciono en la primera posicion de nodo_nuevo
	nodo_nuevo->primero();
	delete (elem->clave);
	delete (elem->dato);
	elem->clave = nodo_nuevo->get_clave_base();
	elem->dato = (TipoInt*)nodo_nuevo->get_dato_base();
	nodo_nuevo->get_clave(elem->clave);
	nodo_nuevo->get_dato(elem->dato);
	//agrego el nuevo separador al indice, identifica al nuevo_nodo
	TipoInt  * dato_  = new TipoInt(0);
	//lo ingreso al padre como separador con sus referencias
	bool result = padre->ingresar_elemento(elem->clave,dato_);
	delete (dato_);
	
	elem->izq = hijo->get_bloque()->get_num_bloque();
	elem->der = nodo_nuevo->get_bloque()->get_num_bloque();
	
	if (result) {
		//asigno los nuevos valores para derecho del nodo_hijo, el padre esta posicionado en ese separador
		padre->set_ref_der(elem->der);
		padre->set_ref_izq(elem->izq);
	}
	
	//le seteo como siguiente el siguiente del nodo antes de partirse y a este
	//ultimo le asigno como sig el nuevo
	nodo_nuevo->set_sig_nodo(nodo_hijo->get_sig_nodo());
	nodo_hijo->set_sig_nodo(nodo_nuevo->get_bloque()->get_num_bloque());
	
	//guardo los hijos y el padre
	Buffer::get_instance()->guardar_bloque(*this, nodo_nuevo->get_bloque());
	Buffer::get_instance()->guardar_bloque(*this, nodo_hijo->get_bloque());
	if (result)
		Buffer::get_instance()->guardar_bloque(*this, padre->get_bloque());		
	
	delete (nodo_nuevo->get_bloque());
	delete (nodo_nuevo);
	delete (nodo_hijo);
	return result;
}

void ArbolBMas::verif_cambio_clave (Nodo * nodo, TipoDato * clave, void ** param){
	ElemNodo* elem = NULL;
	nodo->buscar_elemento(clave);
	if (!nodo->anterior()) {
		elem = new ElemNodo;
		TipoDato* aux = nodo->get_clave_base();
		nodo->get_clave(aux);
		elem->clave = aux;
		elem->dato = (TipoInt*) nodo->get_dato_base();
		nodo->get_dato(elem->dato);
		elem->der = Nodo::BAD_REF;
		elem->izq = Nodo::BAD_REF;
		*param = elem;
	} else
		nodo->siguiente();		
}

void ArbolBMas::cambiar_clave_padre (Nodo * nodo, void ** param){
	ElemNodo* elem = (ElemNodo*) *param;
	unsigned short ref_der = nodo->get_ref_der();
	unsigned short ref_izq = nodo->get_ref_izq();
	nodo->quitar_elemento();
	nodo->ingresar_elemento(elem->clave, elem->dato);	
	nodo->set_ref_der(ref_der);
	nodo->set_ref_izq(ref_izq);
	Buffer::get_instance()->guardar_bloque(*this, nodo->get_bloque());
	//corto la cadena
	delete (elem->clave);
	delete (elem->dato);
	delete (elem);
	*param = NULL;
}

bool ArbolBMas::quitar_interno(Nodo * nodo, TipoDato * clave, void ** param){
	bool quito;
	if( !nodo->es_hoja() ){
		Nodo * hijo = NULL;
		bool hijo_derecho = false;
		//me posiciona donde tiene que ir
		nodo->buscar_elemento(clave);
		//si la clave donde encontre es menor me meto por la izquierda,
		//caso contrario voy por la derecha.
		TipoDato * clave_actual = clave->clonar();
		nodo->get_clave(clave_actual);
		TipoInt * dato_base = new TipoInt(); //asi ocupa 4 B =P
		if( (*clave) < (*clave_actual) )
			hijo = new Nodo(Buffer::get_instance()->get_bloque(*this, nodo->get_ref_izq()), clave,dato_base);
		else{
			hijo_derecho = true;
			hijo = new Nodo(Buffer::get_instance()->get_bloque(*this, nodo->get_ref_der()), clave,dato_base);
		}
		delete clave_actual;
		delete dato_base;
		quito = quitar_interno(hijo, clave, param);
		bool esta = nodo->buscar_elemento(clave);
		//SI QUITO, SE ENCUENTRA LA CLAVE EN EL NODO ACTUAL, Y PARAMETRO QUE
		//ME LLEGA EXISTE (SE MODIF EL PRIMER ELEM EN UNA HOJA)
		if ((quito) && (esta) && (*param !=NULL))
			cambiar_clave_padre(nodo, param);	
		//si quito y quedo en underflow el nodo, lo manejo
		if( quito && hay_underflow(hijo) )
			manejar_underflow( nodo, hijo, hijo_derecho );
		delete (hijo->get_bloque());
		delete hijo;
	}
	else{
		quito = nodo->quitar_elemento(clave);
		if(quito) {
			Buffer::get_instance()->guardar_bloque(*this, nodo->get_bloque());
			verif_cambio_clave(nodo, clave, param);
		}
		//en el caso de una hoja solo intento quitar y devuelvo si fue exitoso
	}	

	return quito;
}

bool ArbolBMas::quitar(TipoDato* clave) throw(ExcepArchCerrado, ExcepErrorTipos, ExcepLeerBloque){
	bool quito = false;
	
	if( fd != -1){
		assert(base != NULL);//ESTO ROMPE SI NO HICIERON LAS COSAS BIEN
		
		if( clave->get_codigo_tipo() != base->get_codigo_tipo() )
			throw ExcepErrorTipos("Error - La clave es de tipo incorrecto");
		
		Debug::get_instance()->mostrar_mensaje("<ARBOL> Se quita en el arbol " + this->get_nombre() + "." );
		//obtengo la raiz
		Bloque * raiz = Buffer::get_instance()->get_bloque(*this,_NODO_RAIZ_);
		//creo un nodo nuevo, le paso estos valores porque ya estan
		//verificados los tipos
		TipoInt * dato = new TipoInt();
		Nodo * nodo_raiz = new Nodo(raiz, clave, dato);
		delete dato;
		//llamo al quitar recursivo, si devuelve false quiere decir
		//que no lo pudo quitar, caso contrario devuelve true
		ElemNodo* ptrelem = NULL;
		void** ptr = (void**) &ptrelem;
		quito = quitar_interno(nodo_raiz ,clave, ptr);
		
		if (*ptr != NULL) {
			ElemNodo* elem = (ElemNodo*) *ptr;
			delete (elem->clave);
			delete (elem->dato);
			delete (elem);	
		}
		
		delete nodo_raiz;
		delete raiz;
			
	}
	else
		throw ExcepArchCerrado("Error - El archivo : "+ this-> get_nombre() +" esta cerrado. ");
	return quito;
}

void ArbolBMas::consultar_interno(Nodo * nodo, TipoDato * clave, TipoInt ** retorno ){
	//los datos siempre debe encontralos en las hojas
	//condicion de corte: nivel 0
	if( nodo->get_nivel() == 0 ){
		if (!nodo->vacio()) {
			(*retorno) = new TipoInt(0);
			//Busco la clave en el nodo
			if (nodo->buscar_elemento(clave))
				//si la encuentro la devuelvo
				nodo->get_dato(*retorno);
			else {
				//Sino obtengo la clave, si es mayor a la que estoy consultando
				TipoDato* clave_act = base->clonar();
				nodo->get_clave(clave_act);
				if ((*clave) < (*clave_act))
					//busco el anterior (si tiene) y lo devuelvo, sino devuelvo el inmediatamente superior
					nodo->anterior();
				nodo->get_dato(*retorno);
				delete (clave_act);
			}
			//pongo nodo actual como el encontrado
			_nodo_actual_ = nodo->get_bloque()->get_num_bloque();
			if (_clave_actual_ != NULL)
				delete (_clave_actual_);
			_clave_actual_ = base->clonar();
			nodo->get_clave(_clave_actual_);
		} else
			retorno = NULL;
	}
	else{
		nodo->buscar_elemento(clave);
		TipoDato* clave_actual = base->clonar();
		nodo->get_clave(clave_actual);
		//si la clave donde encontre es menor me meto por la izquierda,
		//caso contrario voy por la derecha
		Nodo * hijo = NULL;
		if ( (*clave) < (*clave_actual) ) {
			TipoInt dato;
			hijo = new Nodo(Buffer::get_instance()->get_bloque(*this, nodo->get_ref_izq()), clave,&dato);
		}
		else{
			TipoInt dato;
			hijo = new Nodo(Buffer::get_instance()->get_bloque(*this, nodo->get_ref_der()), clave,&dato);
		}
		consultar_interno(hijo, clave, retorno);
		delete (hijo->get_bloque());
		delete hijo;
		delete(clave_actual);
	}
}

TipoInt* ArbolBMas::get_siguiente() {
	if (_clave_actual_ != NULL) {
		TipoInt* retorno = new TipoInt (Nodo::BAD_REF);
		NodoBMas nodo (Buffer::get_instance()->get_bloque(*this, _nodo_actual_), base, retorno);
		nodo.buscar_elemento(_clave_actual_);
		if (nodo.siguiente()) {
			nodo.get_dato(retorno);
			delete (_clave_actual_);
			_clave_actual_ = base->clonar();
			nodo.get_clave(_clave_actual_);
		} else {
			unsigned int sig = nodo.get_sig_nodo();
			if (sig != Nodo::BAD_REF) {
				NodoBMas nodo_sig (Buffer::get_instance()->get_bloque(*this, sig), base, retorno);
				nodo_sig.primero();
				nodo_sig.get_dato(retorno);
				_nodo_actual_ = nodo.get_bloque()->get_num_bloque();
				delete (_clave_actual_);
				_clave_actual_ = base->clonar();
				nodo_sig.get_clave(_clave_actual_);
				delete (nodo_sig.get_bloque());
			} else {
				delete (retorno);
				retorno = NULL;	
			}
		}
		/*if ((retorno != NULL) && (retorno->get_valor() == Nodo::BAD_REF)) {
			delete (retorno);
			retorno = NULL;	
		}*/
		delete (nodo.get_bloque());
		return retorno;
	}
	return NULL;	
}

void ArbolBMas::overflow_en_raiz(Nodo * raiz, ElemNodo * elem) {
	
	if (raiz->get_nivel() != 0)
		ArbolB::overflow_en_raiz(raiz, elem);
	else {
		
		Debug::get_instance()->mostrar_mensaje("<ARBOL> Se produjo overflow en la raiz del arbol " + this->get_nombre() + "." );	
		//pido dos bloques libres, porque la raiz siempre va a necesitar 2.
		//creo los nodos derechos e izquierdos
		Bloque * derecho = get_bloque_libre(raiz->get_nivel() );
		NodoBMas* nodo_derecho = new NodoBMas(derecho, elem->clave, elem->dato);
		Bloque * izquierdo = get_bloque_libre(raiz->get_nivel() );
		NodoBMas* nodo_izquierdo = new NodoBMas(izquierdo, elem->clave, elem->dato);
		
		//intercambio con el derecho. 
		//El derecho queda con el nivel que tenia el padre
		char * temp = raiz->get_bloque()->get_contenido();
		izquierdo->set_contenido(temp, derecho->get_size() );
		delete[] temp;
		raiz->vaciar();
		
		//divido entre el derecho y el izquierdo. Ambos quedan con el mismo
		//nivel, que es el que era de la raiz	
		nodo_izquierdo->ingresar_con_split(nodo_derecho, elem->clave, elem->dato);
		
		//le setteo un nivel mas que los hijos pero si antes era el cero.
		raiz->set_nivel( nodo_derecho->get_nivel() + 1);
		
		//me posiciono en la primera posicion de nodo_derecho
		nodo_derecho->primero();
		TipoDato* clave_nueva = nodo_derecho->get_clave_base();
		nodo_derecho->get_clave(clave_nueva);

		//agrego el nuevo separador al indice, identifica al nuevo_nodo
		TipoInt  * dato_  = new TipoInt(0);
		//lo ingreso al padre como separador con sus referencias
		raiz->ingresar_elemento(clave_nueva,dato_);
		delete (dato_);
		
		//le seteo como siguiente el sigueinte del nodo antes de partirse y a este
		//ultimo le asigno como sig el nuevo
		nodo_derecho->set_sig_nodo(nodo_izquierdo->get_sig_nodo());
		nodo_izquierdo->set_sig_nodo(nodo_derecho->get_bloque()->get_num_bloque());
		
		//asigno el derecho
		raiz->set_ref_der(derecho->get_num_bloque() );
		//asigno el izquierdo
		raiz->set_ref_izq(izquierdo->get_num_bloque() );		
		
		//guardo todos los bloques
		Buffer::get_instance()->guardar_bloque(*this, raiz->get_bloque() );
		Buffer::get_instance()->guardar_bloque(*this, derecho);
		Buffer::get_instance()->guardar_bloque(*this, izquierdo);
		
		//libero los bloques creados
		delete clave_nueva;
		delete derecho;
		delete izquierdo;
		delete nodo_derecho;
		delete nodo_izquierdo;
	}
}

void ArbolBMas::consultar_interno_exacto(Nodo * nodo, TipoDato * clave, TipoInt ** retorno ){
	//los datos siempre debe encontralos en las hojas
	//condicion de corte: nivel 0
	if( nodo->get_nivel() == 0 ){
		if (!nodo->vacio()) {
			(*retorno) = new TipoInt(0);
			//Busco la clave en el nodo
			if (nodo->buscar_elemento(clave))
				//si la encuentro la devuelvo
				nodo->get_dato(*retorno);
			else {
				delete (*retorno);
				*retorno = NULL;
			}
			//pongo nodo actual como el encontrado
			_nodo_actual_ = nodo->get_bloque()->get_num_bloque();
			if (_clave_actual_ != NULL)
				delete (_clave_actual_);
			_clave_actual_ = base->clonar();
			nodo->get_clave(_clave_actual_);
		} else
			*retorno = NULL;
	}
	else{
		nodo->buscar_elemento(clave);
		TipoDato* clave_actual = base->clonar();
		nodo->get_clave(clave_actual);
		//si la clave donde encontre es menor me meto por la izquierda,
		//caso contrario voy por la derecha
		Nodo * hijo = NULL;
		if ( (*clave) < (*clave_actual) ) {
			TipoInt dato;
			hijo = new Nodo(Buffer::get_instance()->get_bloque(*this, nodo->get_ref_izq()), clave,&dato);
		}
		else{
			TipoInt dato;
			hijo = new Nodo(Buffer::get_instance()->get_bloque(*this, nodo->get_ref_der()), clave,&dato);
		}
		consultar_interno_exacto(hijo, clave, retorno);
		delete (hijo->get_bloque());
		delete hijo;
		delete(clave_actual);
	}
}

TipoInt * ArbolBMas::consultar_exacto(TipoDato * clave) throw(ExcepArchCerrado,ExcepLeerBloque){
	TipoInt * retorno = NULL;
	if (this-> fd != -1){
		//obtengo la raiz
		Bloque * raiz = Buffer::get_instance()->get_bloque(*this,_NODO_RAIZ_);
		//creo un nodo nuevo, le paso estos valores porque ya estan
		//verificados los tipos
		TipoInt base_dato(0);
		Nodo * nodo_raiz = new Nodo(raiz,clave, &base_dato);
		consultar_interno_exacto(nodo_raiz,clave, &retorno);
		
		delete raiz;
		delete nodo_raiz;
	}
	else
		throw ExcepArchCerrado("Error - El archivo : "+ this-> get_nombre() +" esta cerrado. ");	
	
	return retorno;	
}
